
package org.biogroovy.search.eutils

import groovy.util.logging.Slf4j

import javax.xml.parsers.DocumentBuilderFactory

import org.biogroovy.eutils.EUtilsURLFactory;
import org.biogroovy.io.eutils.EntrezGeneReader;
import org.biogroovy.models.Gene
import org.biogroovy.models.GeneOntology
import org.biogroovy.search.IResultBuilder
import org.biogroovy.search.SearchException
import org.biogroovy.search.SearchParam
import org.biogroovy.search.SearchResult

/**
 * This search engine searches NCBI's Entrez Gene database.
 *
 */
@Slf4j
class EntrezGeneSearchEngine extends AbsEntrezSearchEngine {

	/** The name of the search engine */
	private static final String NAME = "EntrezGene";

	/** The URL of the pubmed server */
	private static final String URL = "http://www.ncbi.nlm.nih.gov/gene/";
	
	/**
	 * Constructor.
	 */
	public EntrezGeneSearchEngine(){
		super();
		resultBuilder = new EntrezGeneResultBuilder();
	}

	@Override
	public String getName() {
		return NAME;
	}

	@Override
	public String getURLTemplate() {
		return EUtilsURLFactory.getURL(EUtilsURLFactory.ESEARCH, ["db":EUtilsURLFactory.DB_GENE])
	}



	@Override
	public List<SearchResult> doSearch(Map<String, String> parameters)
	throws SearchException {

		List<SearchResult<Gene>> results = new ArrayList<>();

		// do the initial search
		def builder  = DocumentBuilderFactory.newInstance().newDocumentBuilder();
		def root     = builder.parse(bind(parameters)).documentElement

		EntrezGeneReader reader = new EntrezGeneReader();
		List<String> idList = reader.parseList(root, "//Id");
		log.info "idList: " +idList;

		// fetch the articles
		String fetchURL = EUtilsURLFactory.getURL(EUtilsURLFactory.EFETCH, [db:EUtilsURLFactory.DB_GENE]);
		List<Gene> geneList = reader.readList(bind(fetchURL,[id:idList.join(","), retmode:'xml']));
		
		SearchResult<Gene> result = null;
		IResultBuilder<Gene> resultBuilder = getResultBuilder();
		for(Gene gene: geneList){
			result = resultBuilder.convert(gene);
			results.add(result);
		}


		return results;
	}
	
	@Override
	protected void initSearchParams(){
		SearchParam db = new SearchParam(name:'db', value:EUtilsURLFactory.DB_GENE, isRequired:true, isEditable: false );
		SearchParam term = new SearchParam(name:"term", isRequired: true, isTerm: true);
		SearchParam symbol = new SearchParam(name:"Symbol", isRequired:false, isEditable:true, isSubTerm: true );
		SearchParam org = new SearchParam(name:"Organism", isRequired:false, isEditable: true, isSubTerm: true);
		org.setAllowableValues('Homo sapiens','Mus musculus','Rattus norvegicus','Danio rerio','Saccharomyces cervisiae');
		
		getSearchParameters().addAll(db, term, symbol, org);
	}
	
	/**
	 * This class converts EntrezGene gene entries, into search results.
	 * 
	 *
	 */
	class EntrezGeneResultBuilder implements IResultBuilder<Gene>{
		
		public EntrezGeneResultBuilder(){
			
		}
		
		@Override
		SearchResult<Gene> convert(Gene gene){
			SearchResult<Gene> result = new SearchResult([title:gene.symbol, description:gene.name]);
			result.url = URL + gene.getAccession();
			result.accession = gene.getAccession();
			result.tags = new ArrayList();
			gene.goComponentList.each{GeneOntology goTerm ->
				if (goTerm.name != null && goTerm.name != ""){
					result.tags.add(goTerm.name);
				}
			}
			
			gene.goFunctionList.each{GeneOntology goTerm ->
				if (goTerm.name != null && goTerm.name != ""){
					result.tags.add(goTerm.name);
				}
			}
			
			gene.goProcessList.each{GeneOntology goTerm ->
				if (goTerm.name != null && goTerm.name != ""){
					result.tags.add(goTerm.name);
				}
			}
			
			result.setResult(gene);
			return result;
		}
	}

}
